﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;

namespace AutoUpdater.Utils
{
    /// <summary>
    /// Http帮助类
    /// </summary>
    public class HttpHelper
    {
        /// <summary>
        /// 判断地址是否有效。
        /// 通过获取HEAD判断。
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static bool IsUrlConnectOk(string url)
        {
            try
            {
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
                req.Method = "HEAD";
                req.Timeout = 5000;
                req.AllowAutoRedirect = false;
                req.UseDefaultCredentials = true;
                HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                return (resp.StatusCode == HttpStatusCode.OK);
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 获取指定URL的服务器时间。
        /// 通过HEAD获取时间，获取失败或异常默认返回本机时间。
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static DateTime? TryGetInternetTime(string url)
        {
            DateTime? datetime = default(DateTime?);
            try
            {
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
                req.Method = "HEAD";
                req.Timeout = 5000;
                req.AllowAutoRedirect = false;
                req.UseDefaultCredentials = true;
                HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                if (resp.StatusCode == HttpStatusCode.OK)
                {
                    foreach (var k in resp.Headers.AllKeys)
                    {
                        if (k == "Date")
                        {
                            var d = resp.Headers[k];
                            if (string.IsNullOrEmpty(d) == false)
                            {
                                datetime = DateTime.Parse(d);
                                break;
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {
                datetime = default(DateTime?);
            }
            return datetime;
        }

        /// <summary>
        /// 获取地址响应内容大小。
        /// 通过获取HEAD判断。
        /// </summary>
        /// <param name="Path"></param>
        /// <returns></returns>
        public static long TryGetResponseSize(string Path)
        {
            long size;
            try
            {
                System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(Path);
                request.Method = "HEAD";
                System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
                size = response.ContentLength;
                response.Close();
            }
            catch
            {
                size = 0L;
            }
            return size;
        }

        /// <summary>
        /// 创建GET方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="contentType">请求Content-Type</param>
        /// <returns></returns>
        public static byte[] HttpGet(string url, string contentType = "application/x-www-form-urlencoded;charset=UTF-8;")
        {
            return GoHttpGet(url, null, false, 100000, contentType, null);
        }

        /// <summary>
        /// 创建GET方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="contentType">请求Content-Type</param>
        /// <returns></returns>
        public static byte[] HttpGet(string url, IDictionary<string, string> parameters, string contentType = "application/x-www-form-urlencoded;charset=UTF-8;")
        {

            return GoHttpGet(GoBuildRequestUrl(url, parameters), null, false, 100000, contentType, null);
        }

        /// <summary>
        /// 创建GET方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <returns></returns>
        public static byte[] HttpGet(string url, IDictionary<string, string> headers, bool keepAlive, string contentType)
        {
            return GoHttpGet(url, headers, keepAlive, 100000, contentType, null);
        }

        /// <summary>
        /// 创建GET方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <returns></returns>
        public static byte[] HttpGet(string url, IDictionary<string, string> headers, bool keepAlive, int timeOut, string contentType)
        {
            return GoHttpGet(url, headers, keepAlive, timeOut, contentType, null);
        }
        /// <summary>
        /// 创建GET方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="decompress">解压缩方式：gzip</param>
        /// <returns></returns>
        public static byte[] HttpGet(string url, IDictionary<string, string> headers, bool keepAlive, string contentType, string decompress)
        {
            return GoHttpGet(url, headers, keepAlive, 100000, contentType, decompress);
        }

        /// <summary>
        /// 创建GET方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="decompress">解压缩方式：gzip</param>
        /// <returns></returns>
        public static byte[] HttpGet(string url, IDictionary<string, string> headers, bool keepAlive, int timeOut, string contentType, string decompress)
        {
            return GoHttpGet(url, headers, keepAlive, timeOut, contentType, decompress);
        }

        /// <summary>
        /// 创建GET方式的HTTPS请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="decompress">解压缩方式：gzip</param>
        /// <returns></returns>
        public static byte[] HttpsGet(string url, IDictionary<string, string> headers, bool keepAlive, int timeOut, string contentType, string decompress, string httpVersion = "1.1")
        {
            return GoHttpsGet(url, headers, keepAlive, timeOut, contentType, decompress, httpVersion);
        }
        /// <summary>
        /// 创建GET方式的HTTPS请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="decompress">解压缩方式：gzip</param>
        /// <returns></returns>
        public static byte[] HttpsGet(string url, IDictionary<string, string> headers, bool keepAlive, string contentType, string decompress, string httpVersion = "1.1")
        {
            return GoHttpsGet(url, headers, keepAlive, 100000, contentType, decompress, httpVersion);
        }

        /// <summary>
        /// 发起POST方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">UTF-8字符串</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <returns></returns>
        public static string HttpPost(string url, string datas, IDictionary<string, string> headers, bool keepAlive, string contentType)
        {
            byte[] respDatas = GoHttpPost(url, null, headers, keepAlive, 100000, contentType, null);
            return respDatas != null ? UTF8Encoding.UTF8.GetString(respDatas, 0, respDatas.Length) : null;
        }

        /// <summary>
        /// 发起POST方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <returns></returns>
        public static string HttpPost(string url, int timeOut = 100000)
        {
            byte[] respDatas = GoHttpPost(url, null, null, false, timeOut, null, null);
            return respDatas != null ? UTF8Encoding.UTF8.GetString(respDatas, 0, respDatas.Length) : null;
        }

        /// <summary>
        /// 发起POST方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">UTF-8字符串</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <returns></returns>
        public static string HttpPost(string url, string datas, IDictionary<string, string> headers, bool keepAlive, int timeOut, string contentType)
        {
            byte[] respDatas = GoHttpPost(url, UTF8Encoding.UTF8.GetBytes(datas), headers, keepAlive, timeOut, contentType, null);
            return respDatas != null ? UTF8Encoding.UTF8.GetString(respDatas, 0, respDatas.Length) : null;
        }

        /// <summary>
        /// 创建POST方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">请求体byte[]</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <returns></returns>
        public static byte[] HttpPost(string url, byte[] datas, bool keepAlive, string contentType)
        {
            return GoHttpPost(url, datas, null, keepAlive, 100000, contentType, null);
        }

        /// <summary>
        /// 创建POST方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">请求体byte[]</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <returns></returns>
        public static byte[] HttpPost(string url, byte[] datas, bool keepAlive, int timeOut, string contentType)
        {
            return GoHttpPost(url, datas, null, keepAlive, timeOut, contentType, null);
        }

        /// <summary>
        /// 创建POST方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">请求体byte[]</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="strcompress">压缩方式：gzip</param>
        /// <returns></returns>
        public static byte[] HttpPost(string url, byte[] datas, bool keepAlive, int timeOut, string contentType, string strcompress)
        {
            return GoHttpPost(url, datas, null, keepAlive, timeOut, contentType, strcompress);
        }

        /// <summary>
        /// 发起POST方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">请求体UTF-8字符串</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="strcompress">压缩方式：gzip</param>
        /// <returns></returns>
        public static string HttpPost(string url, string datas, IDictionary<string, string> headers, bool keepAlive, int timeOut, string contentType, string strcompress)
        {
            byte[] respDatas = GoHttpPost(url, UTF8Encoding.UTF8.GetBytes(datas), headers, keepAlive, timeOut, contentType, strcompress);
            return respDatas != null ? UTF8Encoding.UTF8.GetString(respDatas, 0, respDatas.Length) : null;
        }

        /// <summary>
        /// 发起POST方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">请求体UTF-8字符串</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="strcompress">压缩方式：gzip</param>
        /// <returns></returns>
        public static string HttpPost(string url, string datas, IDictionary<string, string> headers, bool keepAlive, string contentType, string strcompress)
        {
            byte[] respDatas = GoHttpPost(url, UTF8Encoding.UTF8.GetBytes(datas), headers, keepAlive, 100000, contentType, strcompress);
            return respDatas != null ? UTF8Encoding.UTF8.GetString(respDatas, 0, respDatas.Length) : null;
        }

        /// <summary>
        /// 创建POST方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">请求体byte[]</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="strcompress">压缩方式：gzip</param>
        /// <returns></returns>
        public static byte[] HttpPost(string url, byte[] datas, IDictionary<string, string> headers, bool keepAlive, int timeOut, string contentType, string strcompress)
        {
            return GoHttpPost(url, datas, headers, keepAlive, timeOut, contentType, strcompress);
        }

        /// <summary>
        /// 创建POST方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">请求体byte[]</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="strcompress">压缩方式：gzip</param>
        /// <returns></returns>
        public static byte[] HttpPost(string url, byte[] datas, IDictionary<string, string> headers, bool keepAlive, int timeOut, string contentType)
        {
            return GoHttpPost(url, datas, headers, keepAlive, timeOut, contentType, null);
        }
        /// <summary>
        /// 创建POST方式的HTTPS请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">请求体byte[]</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <returns></returns>
        public static string HttpsPost(string url, string datas, IDictionary<string, string> headers, bool keepAlive, string contentType)
        {
            byte[] respDatas = GoHttpPost(url, UTF8Encoding.UTF8.GetBytes(datas), headers, keepAlive, 100000, contentType, null);
            return respDatas != null ? UTF8Encoding.UTF8.GetString(respDatas, 0, respDatas.Length) : null;
        }
        /// <summary>
        /// 创建POST方式的HTTPS请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">请求体byte[]</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <returns></returns>
        public static string HttpsPost(string url, string datas, IDictionary<string, string> headers, bool keepAlive, int timeOut, string contentType)
        {
            byte[] respDatas = GoHttpPost(url, UTF8Encoding.UTF8.GetBytes(datas), headers, keepAlive, timeOut, contentType, null);
            return respDatas != null ? UTF8Encoding.UTF8.GetString(respDatas, 0, respDatas.Length) : null;
        }
        /// <summary>
        /// 创建POST方式的HTTPS请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">请求体byte[]</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="strcompress">压缩方式：gzip</param>
        /// <param name="httpVersion">HTTP版本，默认是1.1</param>
        /// <returns></returns>
        public static byte[] HttpsPost(string url, byte[] datas, IDictionary<string, string> headers, bool keepAlive, string contentType, string strcompress, string httpVersion = "1.1")
        {
            return GoHttpsPost(url, datas, headers, keepAlive, 100000, contentType, strcompress, httpVersion);
        }

        /// <summary>
        /// 创建POST方式的HTTP请求：multipart/form-data
        /// </summary>
        /// <param name="url"></param>
        /// <param name="multipartKv">Multipart的键值对</param>
        /// <param name="headers">请求标头</param>
        /// <param name="timeOut">超时时间</param>
        /// <returns></returns>
        public static byte[] HttpPostMultipart(string url, List<MultipartKeyValue> multipartKv, IDictionary<string, string> headers, int timeOut)
        {
            return GoHttpPostMultipart(url, multipartKv, headers, timeOut);
        }

        /// <summary>
        /// 组装含参数的请求URL。
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="parameters">请求参数映射</param>
        /// <returns>带参数的请求URL</returns>
        public static string BuildRequestUrl(string url, IDictionary<string, string> parameters)
        {
            return GoBuildRequestUrl(url, parameters);
        }

        /// <summary>
        /// 组装含参数的请求URL。
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="queries">一个或多个经过URL编码后的请求参数串</param>
        /// <returns>带参数的请求URL</returns>
        public static string BuildRequestUrl(string url, params string[] queries)
        {
            return GoBuildRequestUrl(url, queries);
        }
        /// <summary>
        /// 组装普通文本请求参数。
        /// </summary>
        /// <param name="parameters">Key-Value形式请求参数字典</param>
        /// <returns>URL编码后的请求数据</returns>
        public static string BuildQuery(IDictionary<string, string> parameters)
        {
            return GoBuildQuery(parameters);
        }

        #region 私有函数

        /// <summary>
        /// 组装普通文本请求参数。
        /// </summary>
        /// <param name="parameters">Key-Value形式请求参数字典</param>
        /// <returns>URL编码后的请求数据</returns>
        private static string GoBuildQuery(IDictionary<string, string> parameters)
        {
            if (parameters == null || parameters.Count == 0)
            {
                return null;
            }

            StringBuilder query = new StringBuilder();
            bool hasParam = false;

            foreach (KeyValuePair<string, string> kv in parameters)
            {
                string name = kv.Key;
                string value = kv.Value;
                // 忽略参数名或参数值为空的参数
                if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value))
                {
                    if (hasParam)
                    {
                        query.Append("&");
                    }

                    query.Append(name);
                    query.Append("=");
                    query.Append(HttpUtility.UrlEncode(value, Encoding.UTF8));
                    hasParam = true;
                }
            }

            return query.ToString();
        }

        /// <summary>
        /// 组装含参数的请求URL。
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="queries">一个或多个经过URL编码后的请求参数串</param>
        /// <returns>带参数的请求URL</returns>
        private static string GoBuildRequestUrl(string url, params string[] queries)
        {
            if (queries == null || queries.Length == 0)
            {
                return url;
            }

            StringBuilder newUrl = new StringBuilder(url);
            bool hasQuery = url.Contains("?");
            bool hasPrepend = url.EndsWith("?") || url.EndsWith("&");

            foreach (string query in queries)
            {
                if (!string.IsNullOrEmpty(query))
                {
                    if (!hasPrepend)
                    {
                        if (hasQuery)
                        {
                            newUrl.Append("&");
                        }
                        else
                        {
                            newUrl.Append("?");
                            hasQuery = true;
                        }
                    }
                    newUrl.Append(query);
                    hasPrepend = false;
                }
            }
            return newUrl.ToString();
        }
        /// <summary>
        /// 组装含参数的请求URL。
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="parameters">请求参数映射</param>
        /// <returns>带参数的请求URL</returns>
        public static string GoBuildRequestUrl(string url, IDictionary<string, string> parameters)
        {
            if (parameters != null && parameters.Count > 0)
            {
                return GoBuildRequestUrl(url, BuildQuery(parameters));
            }
            return url;
        }
        /// <summary>
        /// 创建GET方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="decompress">解压缩方式：gzip</param>
        /// <returns></returns>
        private static byte[] GoHttpGet(string url, IDictionary<string, string> headers, bool keepAlive, int timeOut, string contentType, string decompress)
        {
            HttpWebRequest request = GetHttpGetRequest(url, headers, keepAlive, contentType, timeOut, decompress);

            byte[] resultDatas = null;
            using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
            {
                if (response != null)
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        Stream stream = response.GetResponseStream();
                        if (response.ContentEncoding != null && response.ContentEncoding.ToLower().Contains("gzip"))
                            stream = new GZipStream(stream, CompressionMode.Decompress);

                        byte[] buffer = new byte[2048];//分段缓存
                        int current = 0;
                        while ((current = stream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            ms.Write(buffer, 0, current);
                        }
                        stream.Close();
                        response.Close();
                        resultDatas = ms.ToArray();
                    }
                }
            }
            return resultDatas;
        }

        /// <summary>
        /// 创建GET方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <returns></returns>
        private static byte[] GoHttpGet(string url, IDictionary<string, string> headers, bool keepAlive, string contentType, int timeOut, string strcompress)
        {
            HttpWebRequest request = GetHttpGetRequest(url, headers, keepAlive, contentType, timeOut, strcompress);

            byte[] resultDatas = null;
            using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
            {
                if (response != null)
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        Stream stream = response.GetResponseStream();
                        if (response.ContentEncoding != null && response.ContentEncoding.ToLower().Contains("gzip"))
                            stream = new GZipStream(stream, CompressionMode.Decompress);

                        byte[] buffer = new byte[2048];//分段缓存
                        int current = 0;
                        while ((current = stream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            ms.Write(buffer, 0, current);
                        }
                        stream.Close();
                        response.Close();
                        resultDatas = ms.ToArray();
                    }
                }
            }
            return resultDatas;
        }
        /// <summary>
        /// 创建GET方式的HTTPS请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="decompress">解压缩方式：gzip</param>
        /// <param name="httpVersion">HTTP版本，默认是1.1</param>
        /// <returns></returns>
        private static byte[] GoHttpsGet(string url, IDictionary<string, string> headers, bool keepAlive, int timeOut, string contentType, string decompress, string httpVersion = "1.1")
        {
            //对服务端证书进行有效性校验（非第三方权威机构颁发的证书，如自己生成的，不进行验证，这里返回true）
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback((sender, certificate, chain, errors) =>
            {
                //验证证书处理
                if (errors == SslPolicyErrors.None)
                    return true;
                return false;
            });
            HttpWebRequest request = GetHttpGetRequest(url, headers, keepAlive, contentType, timeOut, decompress);
            request.ProtocolVersion = new Version(httpVersion);  //http版本，默认是1.1

            byte[] resultDatas = null;
            using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
            {
                if (response != null)
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        Stream stream = response.GetResponseStream();
                        if (response.ContentEncoding != null && response.ContentEncoding.ToLower().Contains("gzip"))
                            stream = new GZipStream(stream, CompressionMode.Decompress);

                        byte[] buffer = new byte[2048];//分段缓存
                        int current = 0;
                        while ((current = stream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            ms.Write(buffer, 0, current);
                        }
                        stream.Close();
                        response.Close();
                        resultDatas = ms.ToArray();
                    }
                }
            }
            return resultDatas;
        }

        /// <summary>
        /// 创建POST方式的HTTP请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">请求体byte[]</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="strcompress">压缩方式：gzip</param>
        /// <returns></returns>
        private static byte[] GoHttpPost(string url, byte[] datas, IDictionary<string, string> headers, bool keepAlive, int timeOut, string contentType, string strcompress)
        {
            HttpWebRequest request = GetHttpPostRequest(url, datas, headers, keepAlive, contentType, timeOut, strcompress);

            byte[] resultDatas = null;
            using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
            {
                if (response != null)
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        Stream stream = response.GetResponseStream();
                        if (response.ContentEncoding != null && response.ContentEncoding.ToLower().Contains("gzip"))
                            stream = new GZipStream(stream, CompressionMode.Decompress);

                        byte[] buffer = new byte[2048];//分段缓存
                        int current = 0;
                        while ((current = stream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            ms.Write(buffer, 0, current);
                        }
                        stream.Close();
                        response.Close();
                        resultDatas = ms.ToArray();
                    }
                }

            }
            return resultDatas;
        }

        /// <summary>
        /// 创建POST方式的HTTPS请求
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="datas">请求体byte[]</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="strcompress">压缩方式：gzip</param>
        /// <param name="httpVersion">HTTP版本，默认是1.1</param>
        /// <returns></returns>
        private static byte[] GoHttpsPost(string url, byte[] datas, IDictionary<string, string> headers, bool keepAlive, int timeOut, string contentType, string strcompress, string httpVersion = "1.1")
        {
            //对服务端证书进行有效性校验（非第三方权威机构颁发的证书，如自己生成的，不进行验证，这里返回true）
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback((sender, certificate, chain, errors) =>
            {
                //验证证书处理
                if (errors == SslPolicyErrors.None)
                    return true;
                return false;
            });
            HttpWebRequest request = GetHttpPostRequest(url, datas, headers, keepAlive, contentType, timeOut, strcompress);
            request.ProtocolVersion = new Version(httpVersion);  //http版本

            byte[] resultDatas = null;
            using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
            {
                if (response != null)
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        Stream stream = response.GetResponseStream();
                        if (response.ContentEncoding != null && response.ContentEncoding.ToLower().Contains("gzip"))
                            stream = new GZipStream(stream, CompressionMode.Decompress);

                        byte[] buffer = new byte[2048];//分段缓存
                        int current = 0;
                        while ((current = stream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            ms.Write(buffer, 0, current);
                        }
                        stream.Close();
                        response.Close();
                        resultDatas = ms.ToArray();
                    }
                }
            }
            return resultDatas;
        }

        /// <summary>
        /// 创建POST方式的HTTP请求：multipart/form-data
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="multipartKv">Multipart的键值对</param>
        /// <param name="headers">标头字典</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <returns></returns>
        private static byte[] GoHttpPostMultipart(string url, List<MultipartKeyValue> multipartKv, IDictionary<string, string> headers, int timeOut)
        {
            HttpWebRequest request = GetHttpPostMultipartRequest(url, multipartKv, headers, timeOut);

            byte[] resultDatas = null;
            using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
            {
                if (response != null)
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        Stream stream = response.GetResponseStream();
                        if (response.ContentEncoding != null && response.ContentEncoding.ToLower().Contains("gzip"))
                            stream = new GZipStream(stream, CompressionMode.Decompress);

                        byte[] buffer = new byte[2048];//分段缓存
                        int current = 0;
                        while ((current = stream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            ms.Write(buffer, 0, current);
                        }
                        stream.Close();
                        response.Close();
                        resultDatas = ms.ToArray();
                    }
                }
            }
            return resultDatas;

        }

        /// <summary>
        /// 获取HttpRequest GET
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="strcompress">压缩方式：gzip</param>
        /// <returns></returns>
        private static HttpWebRequest GetHttpGetRequest(string url, IDictionary<string, string> headers, bool keepAlive, string contentType, int timeOut, string strcompress)
        {
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            request.Method = "GET";
            request.Timeout = timeOut <= 0 ? 180000 : timeOut;
            request.KeepAlive = keepAlive;
            request.ContentType = contentType;

            //设置Header信息，如果已存在则覆盖
            if (headers != null && headers.Count > 0)
            {
                foreach (KeyValuePair<string, string> kv in headers)
                {
                    if (!string.IsNullOrEmpty(kv.Key) && !string.IsNullOrEmpty(kv.Value))
                    {
                        if (string.Join(",", request.Headers.AllKeys).ToLower().Contains(kv.Key.ToLower()) == false)
                            request.Headers.Add(kv.Key, kv.Value);
                        else
                            request.Headers[kv.Key] = kv.Value;
                    }

                }
            }

            //设置GZIP压缩
            if (!string.IsNullOrEmpty(strcompress) && strcompress.ToLower() == "gzip")
            {
                if (string.Join(",", request.Headers.AllKeys).ToLower().Contains("Content-Encoding") == false)
                    request.Headers.Add("Content-Encoding", "gzip");
                else
                    request.Headers["Content-Encoding"] = "gzip";
            }

            return request;
        }

        /// <summary>
        /// 获取HttpRequest POST
        /// </summary>
        /// <param name="url">url地址</param>
        /// <param name="headers">标头字典</param>
        /// <param name="keepAlive">是否长连接</param>
        /// <param name="timeOut">超时时间，单位毫秒ms</param>
        /// <param name="contentType">标头Content-Type</param>
        /// <param name="strcompress">压缩方式：gzip</param>
        /// <returns></returns>
        private static HttpWebRequest GetHttpPostRequest(string url, byte[] datas, IDictionary<string, string> headers, bool keepAlive, string contentType, int timeOut, string strcompress)
        {
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            request.Method = "POST";
            request.Accept = "*/*";
            request.Timeout = timeOut <= 0 ? 180000 : timeOut;
            request.KeepAlive = keepAlive;
            request.ContentType = contentType;
            //request.ContentLength = datas != null ? datas.Length : 0;

            //设置Header信息，如果已存在则覆盖
            if (headers != null && headers.Count > 0)
            {
                foreach (KeyValuePair<string, string> kv in headers)
                {
                    if (!string.IsNullOrEmpty(kv.Key) && !string.IsNullOrEmpty(kv.Value))
                    {
                        if (string.Join(",", request.Headers.AllKeys).ToLower().Contains(kv.Key.ToLower()) == false)
                            request.Headers.Add(kv.Key, kv.Value);
                        else
                            request.Headers[kv.Key] = kv.Value;
                    }
                }
            }
            if (request.ContentLength > 0)
            {
                //设置GZIP压缩
                if (!string.IsNullOrEmpty(strcompress) && strcompress.ToLower() == "gzip")
                {
                    if (string.Join(",", request.Headers.AllKeys).ToLower().Contains("Content-Encoding") == false)
                        request.Headers.Add("Content-Encoding", "gzip");
                    else
                        request.Headers["Content-Encoding"] = "gzip";

                    MemoryStream ms = new MemoryStream();
                    GZipStream stream = new GZipStream(ms, CompressionMode.Compress);
                    stream.Write(datas, 0, datas.Length);
                    stream.Close();

                    using (MemoryStream gzipStream = ms)
                    {
                        byte[] buffers = gzipStream.ToArray();
                        request.ContentLength = buffers.Length;

                        using (Stream reqStream = request.GetRequestStream())
                        {
                            reqStream.Write(buffers, 0, buffers.Length);
                            reqStream.Close();
                        }
                    }
                }
                else
                {
                    //填充请求数据  
                    Stream reqStream = request.GetRequestStream();
                    reqStream.Write(datas, 0, datas.Length);
                    reqStream.Close();
                }
            }

            return request;
        }

        /// <summary>
        /// 获取HttpRequest POST multipart/form-data
        /// </summary>
        /// <param name="url"></param>
        /// <param name="multipartKv">Multipart的键值对</param>
        /// <param name="headers">请求标头</param>
        /// <param name="timeOut">超时时间</param>
        /// <returns></returns>
        private static HttpWebRequest GetHttpPostMultipartRequest(string url, List<MultipartKeyValue> multipartKv, IDictionary<string, string> headers, int timeOut)
        {
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;

            string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
            byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

            request.Method = "POST";
            request.KeepAlive = true;
            request.ContentType = "multipart/form-data; boundary=" + boundary;
            request.Credentials = System.Net.CredentialCache.DefaultCredentials;
            if (timeOut > 0) request.Timeout = timeOut;

            //设置Header信息，如果已存在则覆盖
            if (headers != null && headers.Count > 0)
            {
                foreach (KeyValuePair<string, string> kv in headers)
                {
                    if (!string.IsNullOrEmpty(kv.Key) && !string.IsNullOrEmpty(kv.Value))
                    {
                        if (string.Join(",", request.Headers.AllKeys).ToLower().Contains(kv.Key.ToLower()) == false)
                            request.Headers.Add(kv.Key, kv.Value);
                        else
                            request.Headers[kv.Key] = kv.Value;
                    }
                }
            }

            using (var rs = request.GetRequestStream())
            {
                // 普通参数模板
                string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
                //带文件的参数模板
                string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
                foreach (MultipartKeyValue item in multipartKv)
                {
                    //如果是普通参数
                    if (string.IsNullOrEmpty(item.FilePath))
                    {
                        rs.Write(boundarybytes, 0, boundarybytes.Length);
                        string formitem = string.Format(formdataTemplate, item.Key, item.Value);
                        byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                        rs.Write(formitembytes, 0, formitembytes.Length);
                    }
                    //如果是文件参数,则上传文件
                    else
                    {
                        rs.Write(boundarybytes, 0, boundarybytes.Length);

                        string header = string.Format(headerTemplate, item.Key, item.FilePath, item.ContentType);
                        byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
                        rs.Write(headerbytes, 0, headerbytes.Length);

                        using (var fileStream = new FileStream(item.FilePath, FileMode.Open, FileAccess.Read))
                        {
                            byte[] buffer = new byte[4096];
                            int bytesRead = 0;
                            long total = 0;
                            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                            {

                                rs.Write(buffer, 0, bytesRead);
                                total += bytesRead;
                            }
                        }
                    }
                }

                byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
                rs.Write(trailer, 0, trailer.Length);
            }
            return request;
        }
        /// <summary>
        /// 验证证书处理
        /// </summary>
        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            if (errors == SslPolicyErrors.None)
                return true;
            return false;
        }
        #endregion

        /// <summary>
        /// POST Multipart数据键值类
        /// </summary>
        public class MultipartKeyValue
        {
            private string _key;
            private string _value;
            private string _filePath;
            private string _contentType = "*/*";

            public string Key
            {
                get { return _key; }
                set { _key = value; }
            }

            /// <summary>
            /// 
            /// </summary>
            public string Value
            {
                get { return _value; }
                set { _value = value; }
            }
            public string FilePath
            {
                get { return _filePath; }
                set { _filePath = value; }
            }
            public string ContentType
            {
                get { return _contentType; }
                set { _contentType = value; }
            }

            public MultipartKeyValue(string key, string value, string filePath, string contentType)
            {
                _key = key;
                _value = value;
                _filePath = filePath;
                _contentType = contentType;
            }

            public MultipartKeyValue() { }

            public MultipartKeyValue(string key, string value, string filePath)
            {
                _key = key;
                _value = value;
                _filePath = filePath;
            }

            public MultipartKeyValue(string key, string value)
            {
                _key = key;
                _value = value;
            }
        }
    }
}
